package com.cloud.prac.controller;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.StopWatch;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.cloud.prac.aop.annotation.ReportLog;
import com.cloud.prac.dao.TestMapper;
import com.cloud.prac.model.ExcelData;
import com.cloud.prac.model.StudentInfo;
import com.prac.common.result.DataResult;
import com.prac.common.result.Page;
import com.prac.common.result.Result;

import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * 大批量Excel数据导出
 * https://mp.weixin.qq.com/s/4QbhTs_OEpWKQTXP48j6kQ
 *
 * @author 24373
 * @version 1.0
 * @date 2024-06-29 16:49
 */
@RestController
@Slf4j
@RequestMapping("/excel")
public class ExcelController {

    private final static int SHEET_COUNT = 100_0000;
    private final static int PER_QUERY = 1_0000;

    @Resource
    private TestMapper testMapper;

    @GetMapping("test")
    @ReportLog(desc = "excel下载测试")
    public DataResult<Integer> download() {
        return new DataResult<>(testMapper.excelListTotal(null));
    }

    @GetMapping("down")
    public ResponseEntity<byte[]> download(@RequestParam Integer period) throws UnsupportedEncodingException {
        List<ExcelData> data = testMapper.excelList(period, new Page(1, 100000));
        StopWatch watch = new StopWatch();
        watch.start();
        final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        EasyExcel.write(outputStream)
                .head(ExcelData.class)
                .excelType(ExcelTypeEnum.XLSX)
                .sheet("数据表")
                .doWrite(data);
        watch.stop();
        log.info("导出耗时：{}", watch.getTotalTimeSeconds());
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDispositionFormData("attachment", new String("导出数据.xlsx".getBytes(StandardCharsets.UTF_8), "ISO8859-1"));
        return new ResponseEntity<>(outputStream.toByteArray(), headers, HttpStatus.OK);
    }

    /**
     * 分批分sheet导出
     *
     * @param period
     * @return
     */
    @GetMapping("down2")
    public ResponseEntity<byte[]> download2(@RequestParam(required = false) Integer period) throws UnsupportedEncodingException {
        Integer count = testMapper.excelListTotal(period);
        //总页数
        int pageCount = count % SHEET_COUNT == 0 ? count / SHEET_COUNT : count / SHEET_COUNT + 1;
        long oneSheetWriteCount = SHEET_COUNT / PER_QUERY;
        // 最后一页的查询次数
        long lastSheetWriteCount = count % SHEET_COUNT == 0 ? oneSheetWriteCount :
                (count % SHEET_COUNT % PER_QUERY == 0 ? ((count % SHEET_COUNT) / PER_QUERY) : ((count % SHEET_COUNT) / PER_QUERY) + 1);
        log.info("总页数：{},oneSheetWriteCount：{},lastSheetWriteCount：{}", pageCount, oneSheetWriteCount, lastSheetWriteCount);
        final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ExcelWriter excelWriter = EasyExcel.write(outputStream).build();
        StopWatch watch1 = new StopWatch();
        watch1.start();
        Page page = new Page();
        page.setPageSize(PER_QUERY);
        for (int i = 0; i < pageCount; i++) {
            // 每页查询的次数 ；判断是否最后一页
            for (int j = 0; j < ((i == pageCount - 1) ? lastSheetWriteCount : oneSheetWriteCount); j++) {
                page.setPageNum(i * SHEET_COUNT + j * PER_QUERY);
                StopWatch watch = new StopWatch();
                watch.start();
                log.info("第{}轮打印page：{}", i, page);
                List<ExcelData> data = testMapper.excelList(period, page);
                WriteSheet sheet = EasyExcel
                        .writerSheet(i, "test-sheet" + i)
                        .head(ExcelData.class)
                        .build();
                // 写入数据
                excelWriter.write(data, sheet);
                watch.stop();
                log.info("每轮打印时间:{}|<|>|数量:{}", watch.getTotalTimeSeconds(), data.size());
            }
        }
        watch1.stop();
        log.info("总打印时间：{}", watch1.getTotalTimeSeconds());
        excelWriter.finish();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDispositionFormData("attachment",
                new String("导出数据.xlsx".getBytes(StandardCharsets.UTF_8), "ISO8859-1")
        );
        return new ResponseEntity<>(outputStream.toByteArray(), headers, HttpStatus.OK);
    }

//    todo 实现多线程并发读并且顺序消费的文件导出

    @GetMapping("import")
    public Result importExcel() {
        testMybatisBatch();
        return new Result();
    }

    //todo 分批分线程打入
    private void testMybatisBatch() {
        List<StudentInfo> list = new ArrayList<>();
        Random random = new Random();
        for (int i = 0; i < 10_0000; i++) {
            list.add(
                    StudentInfo.builder()
                            .studentId(random.nextInt(100000))
                            .name("i" + random.nextInt(100000))
                            .courseId(random.nextInt(10000))
                            .classId(random.nextInt(10000))
                            .createTime(DateTime.now().toSqlDate())
                            .build()
            );
        }
        log.info("加载开始");
        testMapper.insertBatch(list);
        log.info("加载结束");

    }


}
